package com.xdoc.client;

import com.xdoc.client.util.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * XDts客户端
 * @author coffish
 */
public class XDtsClient {
	private final static Log logger = LogFactory.getLog(XDtsClient.class);
	/**
	 * 默认服务器地址
	 */
	public static String DEFAULT_URL = "https://xdts.xdocin.com";
	/**
	 * XDOC服务地址
	 */
	private String url;
	/**
	 * 文件管理账号
	 */
	private String key;
	/**
	 * 服务地址
	 * @return
	 */
	public String getUrl() {
		return url;
	}
	/**
	 * 服务地址
	 * @param url
	 */
	public void setUrl(String url) {
		this.url = url;
	}

	/**
	 * 文件管理账号
	 * @return
	 */
	public String getKey() {
		return key;
	}

	/**
	 * 文件管理账号
	 * @param key
	 */
	public void setKey(String key) {
		this.key = key;
	}

	/**
	 * 构造器
	 */
	public XDtsClient() {
		this(DEFAULT_URL); 
	}
	/**
	 * 构造器
	 * @param url 服务地址
	 */
	public XDtsClient(String url) {
		this.url = url;
		this.key = "";
	}
	/**
	 * 运行文档模板
	 * @param tmplFile 模板文件
	 * @param data 数据
	 * @param targetFile 目标文件
	 * @throws IOException
	 */
	public void run(File tmplFile, Object data, File targetFile) throws IOException {
		this.doRun(new FileInputStream(tmplFile), data, new FileOutputStream(targetFile), IOUtils.getFileFormat(targetFile.getName()));
	}

	/**
	 * 检测模板地址有效性
	 * @param tmplUrl
	 * @throws IOException
	 */
	private void checkTmplUrl(String tmplUrl) throws IOException {
		if (!tmplUrl.startsWith("http:")
				&& !tmplUrl.startsWith("https:")
				&& !tmplUrl.startsWith("xfile:")
				&& !tmplUrl.startsWith("data:")) {
			throw new IOException("无效文档模板地址：" + tmplUrl);
		}
	}
	/**
	 * 运行文档模板
	 * @param tmplUrl 模板文件URL，支持http、datauri
	 * @param data 数据
	 * @param targetFile 目标文件
	 * @throws IOException
	 */
	public void run(String tmplUrl, Object data, File targetFile) throws IOException {
		this.checkTmplUrl(tmplUrl);
		this.doRun(tmplUrl, data, new FileOutputStream(targetFile), IOUtils.getFileFormat(targetFile.getName()));
	}
	/**
	 * 运行文档模板
	 * @param tmplUrl 模板文件URL，支持http、xfile、datauri
	 * @param data 数据
	 * @param out 目标文件流
	 * @param format 格式 docx/xlsx/pptx、pdf、ofd
	 * @throws IOException
	 */
	public void run(String tmplUrl, Object data, OutputStream out, String format) throws IOException {
		this.checkTmplUrl(tmplUrl);
		this.doRun(tmplUrl, data, out, format);
	}
	/**
	 * 运行文档模板
	 * @param in 模板文件流
	 * @param data 数据
	 * @param out 目标文件流
	 * @param format 格式 docx/xlsx/pptx、pdf、ofd、png、jpg
	 * @throws IOException
	 */
	public void run(InputStream in, Object data, OutputStream out, String format) throws IOException {
		this.doRun(in, data, out, format);
	}
	/**
	 * 运行xdoc
	 * @param tmpl 模板文件URL，支持http、datauri
	 * @param data 数据
	 * @param out 输出目标
	 * @param format 目标格式
	 * @throws IOException
	 */
	private void doRun(Object tmpl, Object data, OutputStream out, String format) throws IOException {
		try {
			Map<String, Object> param = new HashMap<String, Object>();
			param.put("func", "run");
			param.put("tmpl", tmpl);
			param.put("data", data);
			param.put("format", format);
			param.put("subformat", "json");
			invoke(param, out);
		} finally {
			out.close();
		}
	}
	/**
	 * 获取模板元数据
	 * @param tmpl 模板文件URL，支持http
	 * @throws IOException
	 */
	public Map<String, String> meta(String tmpl) throws IOException {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("func", "meta");
		param.put("tmpl", tmpl);
		param.put("format", "json");
		return (Map<String, String>) invoke(param);
	}
	/**
	 * 刷新缓存
	 * @param tmpl 模板文件URL，支持http
	 * @throws IOException
	 */
	public void refresh(String tmpl) throws IOException {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("func", "refresh");
		param.put("tmpl", tmpl);
		param.put("format", "json");
		invoke(param);
	}
	/**
	 * 上传模板文件
	 * @param file
	 * @throws IOException
	 */
	public void up(File file) throws IOException {
		this.up(file, true);
	}
	/**
	 * 上传模板文件
	 * @param file
	 * @throws IOException
	 */
	private void up(File file, boolean check) throws IOException {
		if (file.isFile()) {
			if (file.getName().endsWith(".docx")
					|| file.getName().endsWith(".xlsx")
					|| file.getName().endsWith(".pptx")) {
				this.up(file.getName(), new FileInputStream(file));
			} else if (check) {
				throw new IOException(file.getName() + "不是有效的模板文件");
			}
		} else if (file.isDirectory()) {
			File[] list = file.listFiles();
			for (File file2 : list) {
				this.up(file2, false);
			}
		}
	}
	/**
	 * 上传模板文件
	 * @param tmpl
	 * @param in
	 * @throws IOException
	 */
	public void up(String tmpl, InputStream in) throws IOException {
		logger.info("上传模板文件：" + tmpl);
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("func", "up");
		param.put("key", this.key);
		param.put("filename", tmpl);
		param.put("data", IOUtils.toDataURI(in, "xdoc"));
		param.put("format", "json");
		this.invoke(param);
	}
	/**
	 * 下载模板文件
	 * @param tmpl
	 * @param out
	 * @throws IOException
	 */
	public void down(String tmpl, OutputStream out) throws IOException {
		logger.info("下载模板文件：" + tmpl);
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("format", "json");
		ApiInvoker.invoke(this.getUrl() + "/" + IOUtils.urlEncode(tmpl), param, out);
	}
	/**
	 * 删除模板文件
	 * @param tmpl
	 * @throws IOException
	 */
	public void remove(String tmpl) throws IOException {
		logger.info("删除模板文件：" + tmpl);
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("func", "remove");
		param.put("key", this.key);
		param.put("fillename", tmpl);
		param.put("format", "json");
		this.invoke(param);
	}
	/**
	 * 模板文件是否存在
	 * @param tmpl
	 * @throws IOException
	 */
	public boolean exists(String tmpl) throws IOException {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("func", "exists");
		param.put("key", this.key);
		param.put("filename", tmpl);
		param.put("format", "json");
		return "true".equals(this.invoke(param));
	}
	private String getXUrl() {
		return this.url + (this.url.endsWith("/") ? "xdts" : "/xdts");
	}

	private void invoke(Map<String, Object> param, OutputStream out) throws IOException {
		ApiInvoker.invoke(this.getXUrl(), param, out);
	}
	private Object invoke(Map<String, Object> param) throws IOException {
		return ApiInvoker.invoke(this.getXUrl(), param);
	}
}
